﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;

namespace TCPTest
{
    enum AIDifficulty { EASY, MEDIUM, HARD };

    class Player
    {
        public SpaceColor color;
        public Player() { }
        public virtual Move getNextMove(Board board, NetworkStream stream) 
        {
            Move move = new Move();
            return move;
        }
    }

    class RemoteAI : Player
    {
        int port;
        string server;
        NetworkStream remoteStream;

        public RemoteAI() { }
        public RemoteAI(SpaceColor color, string serverAndPort)
        {
            this.color = color;

            serverAndPort = serverAndPort.Substring(serverAndPort.IndexOf(' ')+1); // remove "ai-ai"
            string serverStr = serverAndPort.Substring(0, serverAndPort.IndexOf(' '));
            string portStr = serverAndPort.Substring(serverAndPort.LastIndexOf(' ')+1);
            port = Convert.ToInt32(portStr);


            //Open NetworkStream for this AI to use
            byte[] data = new byte[1024];
            string input, stringData;
            TcpClient server;

            TcpListener tcpListener = new TcpListener(port);
            tcpListener.Start();
            server = tcpListener.AcceptTcpClient();

            remoteStream = server.GetStream();

            int numBytesRead;
            if (server.Available > 0)
                numBytesRead = remoteStream.Read(data, 0, data.Length); // Clear gunk?
        }

        public override Move getNextMove(Board board, NetworkStream ignoreThisStream)  //Ignore this stream!
        {
            string stringData = TCP.GetNextLineFromClient(remoteStream);

            Parser parser = new Parser();

            Move nextMove = parser.parseMove(stringData);
            nextMove.color = color;

            return nextMove;
        }

    }

    class AIPlayer : Player
    {
        AIDifficulty difficulty;
        int HARD_DEPTH = 2;
        int MEDIUM_DEPTH = 1;
        public AIPlayer() { }
        public AIPlayer(AIDifficulty diff, SpaceColor color)
        {
            this.color = color;
            difficulty = diff;
        }

        public override Move getNextMove(Board board, NetworkStream stream) 
        {
            bool allEmpty = true;
            for(byte x = 0; x < 15; x++)
                for (byte y = 0; y < 15; y++)
                {
                    if (board.board[x][y] != SpaceColor.EMPTY)
                    {
                        allEmpty = false;
                        break;
                    }
                }
            if (allEmpty)
                return randomMove(board);

            if (difficulty == AIDifficulty.HARD)
            {
                Minimax minimax = new Minimax(board, color, HARD_DEPTH);
                Move bestMove = minimax.getBestMove(HARD_DEPTH);
                bestMove.color = color;
                return bestMove;
            }
            else if (difficulty == AIDifficulty.MEDIUM)
            {
                Minimax minimax = new Minimax(board, color, MEDIUM_DEPTH);
                Move bestMove = minimax.getBestMove(MEDIUM_DEPTH);
                bestMove.color = color;
                return bestMove;
            }
            else //easy move, random.
            {
                return randomMove(board);
            }
        }

        private Move randomMove(Board board)
        {
            Random rand = new Random();
            int randomCount = 0;
            while (randomCount < 10000) //try a bunch of random moves
            {
                byte x = (byte)(rand.Next() % 15);
                byte y = (byte)(rand.Next() % 15);
                if (board.board[x][y] == SpaceColor.EMPTY)
                    return new Move(x, y, color);
            }

            for (byte i = 0; i < 15; i++) //check for ANY open move
                for (byte j = 0; j < 15; j++)
                    if (board.board[i][j] == SpaceColor.EMPTY)
                        return new Move(i, j, color);

            throw new Exception("Board is full, cannot make a move!");
        }
    }

    class Human : Player
    {
        public Human(SpaceColor color) {
            this.color = color;
        }

        public override Move getNextMove(Board board, NetworkStream stream)
        {
            string stringData = TCP.GetNextLineFromClient(stream);

            Parser parser = new Parser();

            Move nextMove = parser.parseMove(stringData);
            nextMove.color = color;

            return nextMove;
        }
    }
}
